#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
#include <alsa/asoundlib.h>

// 打开并初始化混音器
int init_mixer(const char *card, const char *selem_name, snd_mixer_t **handle, snd_mixer_elem_t **elem)
{
    int err;
    snd_mixer_selem_id_t *sid;

    // 打开混音器
    if ((err = snd_mixer_open(handle, 0)) < 0)
    {
        fprintf(stderr, "Mixer %s open error: %s\n", card, snd_strerror(err));
        return err;
    }

    // 附加控制接口到混音器
    if ((err = snd_mixer_attach(*handle, card)) < 0)
    {
        fprintf(stderr, "Mixer attach %s error: %s\n", card, snd_strerror(err));
        snd_mixer_close(*handle);
        return err;
    }

    // 注册混音器
    if ((err = snd_mixer_selem_register(*handle, NULL, NULL)) < 0)
    {
        fprintf(stderr, "Mixer register error: %s\n", snd_strerror(err));
        snd_mixer_close(*handle);
        return err;
    }

    // 加载混音器元素
    if ((err = snd_mixer_load(*handle)) < 0)
    {
        fprintf(stderr, "Mixer %s load error: %s\n", card, snd_strerror(err));
        snd_mixer_close(*handle);
        return err;
    }

    // 分配简单元素ID
    snd_mixer_selem_id_alloca(&sid);
    snd_mixer_selem_id_set_name(sid, selem_name);

    // 查找简单元素
    *elem = snd_mixer_find_selem(*handle, sid);
    if (!*elem)
    {
        fprintf(stderr, "Unable to find simple control '%s',%i\n", selem_name, 0);
        snd_mixer_close(*handle);
        return -ENOENT;
    }

    return 0;
}

/**
 * 设置音频采集或音频回放的开关函数
 * 使用：./control <playback|capture> <on|off>
 * @param card：声卡名称
 * @param selem_name：控制项名称 <Capture|Playback>
 * @param enable：控制参数 <true|false>
 */
int set_audio_switch(const char *card, const char *selem_name, bool enable)
{
    int err;
    snd_mixer_t *handle = NULL;
    snd_mixer_elem_t *elem = NULL;
    const char *selem = NULL;

    if (strcasecmp(selem_name, "CAPTURE") == 0)
    {
        selem = "Capture";
    }
    else if (strcasecmp(selem_name, "PLAYBACK") == 0)
    {
        selem = "PCM";
    }
    else
    {
        fprintf(stderr, "Invalid type: %s. Use PLAYBACK or CAPTURE.\n", selem_name);
        return -EINVAL;
    }

    // 初始化混音器
    if ((err = init_mixer(card, selem, &handle, &elem)) < 0)
    {
        return err;
    }

    // 设置开关
    if (strcasecmp(selem_name, "PLAYBACK") == 0)
    {
        if ((err = snd_mixer_selem_set_playback_switch_all(elem, enable ? 1 : 0)) < 0)
        {
            fprintf(stderr, "Unable to set Playback switch: %s\n", snd_strerror(err));
            goto cleanup;
        }
    }
    else if (strcasecmp(selem_name, "CAPTURE") == 0)
    {
        if ((err = snd_mixer_selem_set_capture_switch_all(elem, enable ? 1 : 0)) < 0)
        {
            fprintf(stderr, "Unable to set Capture switch: %s\n", snd_strerror(err));
            goto cleanup;
        }
    }

    // 成功
    err = 0;

cleanup:
    if (handle)
    {
        // 关闭混音器
        snd_mixer_close(handle);
    }
    return err;
}

/**
 * 获取音频采集通道音量
 * @param card： 声卡名称
 * @param selem： 控制项
 */
int get_capture_volume(const char *card, const char *selem)
{
    int err;
    snd_mixer_t *handle;
    snd_mixer_elem_t *elem;

    // 初始化混音器
    if ((err = init_mixer(card, selem, &handle, &elem)) < 0)
    {
        return err;
    }

    // 获取采集通道音量
    long volume = 0;
    if ((err = snd_mixer_selem_get_capture_volume(elem, 0, &volume)) < 0)
    {
        fprintf(stderr, "Unable to get capture volume: %s\n", snd_strerror(err));
        snd_mixer_close(handle);
        return err;
    }

    // 关闭混音器
    snd_mixer_close(handle);
    return volume; // 成功返回音量
}

/**
 * 获取音频采集通道音量
 * @param card： 声卡名称
 * @param selem： 控制项
 */
int get_playback_volume(const char *card, const char *selem)
{
    int err;
    snd_mixer_t *handle;
    snd_mixer_elem_t *elem;

    // 初始化混音器
    if ((err = init_mixer(card, selem, &handle, &elem)) < 0)
    {
        return err;
    }

    // 获取回放通道音量
    long volume = 0;
    if ((err = snd_mixer_selem_get_playback_volume(elem, 0, &volume)) < 0)
    {
        fprintf(stderr, "Unable to get playback volume: %s\n", snd_strerror(err));
        snd_mixer_close(handle);
        return err;
    }

    // 关闭混音器
    snd_mixer_close(handle);
    return volume; // 成功返回音量
}

/**
 * 获取音频回放音量范围
 * @param card：声卡名称
 * @param selem：控制项名称
 * @param min_volume：指向最小音量的指针
 * @param max_volume：指向最大音量的指针
 * @return：成功返回0，失败返回负错误码
 */
int get_playback_volume_range(const char *card, const char *selem, long *min_volume, long *max_volume)
{
    int err;
    snd_mixer_t *handle;
    snd_mixer_elem_t *elem;

    // 初始化混音器
    if ((err = init_mixer(card, selem, &handle, &elem)) < 0)
    {
        return err;
    }

    // 获取回放音量范围
    if ((err = snd_mixer_selem_get_playback_volume_range(elem, min_volume, max_volume)) < 0)
    {
        fprintf(stderr, "Unable to get playback volume range: %s\n", snd_strerror(err));
        snd_mixer_close(handle);
        return err;
    }

    // 关闭混音器
    snd_mixer_close(handle);
    return 0;
}

/**
 * 设置音频采集音量
 * @param card：声卡名称
 * @param selem：控制项名称
 * @param volume：指向要设置的音量值的指针
 * @return：成功返回0，失败返回负错误码
 */
int set_capture_volume(const char *card, const char *selem, long *volume)
{
    int err;
    snd_mixer_t *handle;
    snd_mixer_elem_t *elem;

    // 初始化混音器
    if ((err = init_mixer(card, selem, &handle, &elem)) < 0)
    {
        return err;
    }

    // 获取音量范围
    long min, max;
    if ((err = snd_mixer_selem_get_capture_volume_range(elem, &min, &max)) < 0)
    {
        fprintf(stderr, "Unable to get capture volume range: %s\n", snd_strerror(err));
        snd_mixer_close(handle);
        return err;
    }

    // 限制音量范围
    if (*volume < min)
        *volume = min;
    if (*volume > max)
        *volume = max;

    // 设置采集通道音量
    if ((err = snd_mixer_selem_set_capture_volume_all(elem, *volume)) < 0)
    {
        fprintf(stderr, "Unable to set capture volume: %s\n", snd_strerror(err));
        snd_mixer_close(handle);
        return err;
    }

    // 关闭混音器
    snd_mixer_close(handle);
    return 0;
}

/**
 * 设置音频回放通道音量
 * @param card：声卡名称
 * @param selem：控制项名称
 * @param volume：指向要设置的音量值的指针
 * @return：成功返回0，失败返回负错误码
 */
int set_playback_volume(const char *card, const char *selem, long *volume)
{
    int err;
    snd_mixer_t *handle;
    snd_mixer_elem_t *elem;

    // 初始化混音器
    if ((err = init_mixer(card, selem, &handle, &elem)) < 0)
    {
        return err;
    }

    // 获取音量范围
    long min, max;
    if ((err = snd_mixer_selem_get_playback_volume_range(elem, &min, &max)) < 0)
    {
        fprintf(stderr, "Unable to get playback volume range: %s\n", snd_strerror(err));
        snd_mixer_close(handle);
        return err;
    }

    // 限制音量范围
    if (*volume < min)
        *volume = min;
    if (*volume > max)
        *volume = max;

    // 设置回放通道音量
    if ((err = snd_mixer_selem_set_playback_volume_all(elem, *volume)) < 0)
    {
        fprintf(stderr, "Unable to set playback volume: %s\n", snd_strerror(err));
        snd_mixer_close(handle);
        return err;
    }

    // 关闭混音器
    snd_mixer_close(handle);
    return 0;
}

/**
 * 处理开关操作
 * @param card：声卡名称
 * @param type：操作类型
 * @param command：开关命令
 * @return：成功返回0，失败返回负错误码
 */
int handle_switch(const char *card, const char *type, const char *command)
{
    bool enable;
    if (strcasecmp(command, "ON") == 0)
    {
        enable = true;
    }
    else if (strcasecmp(command, "OFF") == 0)
    {
        enable = false;
    }
    else
    {
        fprintf(stderr, "Invalid argument: %s. Use on or off.\n", command);
        return -1;
    }

    int ret = set_audio_switch(card, type, enable);
    if (ret != 0)
    {
        fprintf(stderr, "Failed to set %s channel: %s\n", type, snd_strerror(ret));
        return ret;
    }

    printf("%s channel %s successfully.\n", type, enable ? "enabled" : "disabled");
    return 0;
}

/**
 * 处理音量操作
 * @param card：声卡名称
 * @param type：操作类型
 * @param value：音量值
 * @return：成功返回0，失败返回负错误码
 */
int handle_volume(const char *card, const char *type, long value)
{
    int ret;
    if (strcasecmp(type, "PLAYBACK") == 0)
    {
        ret = set_playback_volume(card, "PCM", &value);
    }
    else if (strcasecmp(type, "CAPTURE") == 0)
    {
        ret = set_capture_volume(card, "Capture", &value);
    }
    else
    {
        fprintf(stderr, "Invalid type: %s. Use playback or capture.\n", type);
        return -1;
    }

    if (ret < 0)
    {
        fprintf(stderr, "Failed to set %s volume: %s\n", type, snd_strerror(ret));
        return ret;
    }

    printf("%s volume set to %ld successfully.\n", type, value);
    return 0;
}

/**
 * 处理音频控制操作
 * @param card：声卡名称
 * @param argc：参数个数
 * @param argv：参数数组
 * @return：成功返回0，失败返回负错误码
 */
int process_audio_control(const char *card, int argc, char **argv)
{
    // 检查命令行参数数量是否正确
    if (argc < 3 || argc > 4)
    {
        fprintf(stderr, "Usage: %s <playback|capture> <on|off> or %s <playback|capture> <volume> <value>\n", argv[0], argv[0]);
        return 1;
    }

    int ret = 0;

    // 处理开关操作
    if (argc == 3)
    {
        ret = handle_switch(card, argv[1], argv[2]);
    }
    else if (argc == 4) // 处理音量操作
    {
        // 检查命令参数
        if (strcasecmp(argv[2], "VOLUME") != 0)
        {
            fprintf(stderr, "Invalid argument: %s. Use volume.\n", argv[2]);
            return 1;
        }

        long volume = atol(argv[3]);
        ret = handle_volume(card, argv[1], volume);
    }

    return ret;
}